diff --git a/source_code/.gitignore b/source_code/.gitignore
index 380ca78..d35051d 100644
--- a/source_code/.gitignore
+++ b/source_code/.gitignore
@@ -15,6 +15,7 @@ game_script_native.implib
 game_script_native.lib
 gamescript.dll
 gamescript.dll.lib
+gamescript.lib
 gamescript.exp
 gamescript_library_procedures.dll
 gamescript_library_procedures.exp
diff --git a/source_code/gamescript.h b/source_code/gamescript.h
index bb39b9b..f613ec6 100644
--- a/source_code/gamescript.h
+++ b/source_code/gamescript.h
@@ -31,6 +31,10 @@
 #pragma comment(lib, "lib/windows7-x64/common.lib")
 #pragma comment(lib, "lib/windows7-x64/renderer.lib")
 #pragma comment(lib, "lib/windows7-x64/rtcore.lib")
+#undef File
+#undef Filter
+#include <shlobj.h>  // For SHGetKnownFolderPath
+#include <strsafe.h> // For StringCchCopyW
 #include <windows.h>
 #include "framework/redgpu_f.h"
 #include "framework/cimgui.h"
diff --git a/source_code/gamescript_imgui_custom_input_text_multiline.cpp b/source_code/gamescript_imgui_custom_input_text_multiline.cpp
index 00fc6da..81b1625 100644
--- a/source_code/gamescript_imgui_custom_input_text_multiline.cpp
+++ b/source_code/gamescript_imgui_custom_input_text_multiline.cpp
@@ -6,14 +6,947 @@ using namespace ImGui;
 
 // NOTE(Constantine): For overriding key presses in Dear ImGui.
 #include <string>
+extern uint64_t g_codeCurrentLineNumber;
 extern int g_dearImGuiGoToLine;
+extern int g_dearImGuiGoToCharPosition;
+extern int g_dearImGuiGoToCharPositionSelectionStart;
+extern int g_dearImGuiGoToCharPositionSelectionEnd;
+extern bool g_scrollCode;
 
 // NOTE(Constantine): using bigger undos for GameScriptImGuiInputTextMultiline only.
 ImStb::StbUndoRecord  ImStb::gGameScriptImGuiStb_undo_rec[STB_TEXTEDIT_UNDOSTATECOUNT] = {};
 STB_TEXTEDIT_CHARTYPE ImStb::gGameScriptImGuiStb_undo_char[STB_TEXTEDIT_UNDOCHARCOUNT] = {};
 
-bool GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data)
+extern "C" void igImDrawListAddTextW(ImDrawList* drawList, const ImFont* font, float font_size, const ImVec2 pos, ImU32 col, const wchar_t* text_begin, const wchar_t* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect);
+extern "C" void profileBegin (const char * label);
+extern "C" void profileEnd   (const char * label);
+
+extern uint64_t g_display_text_line_count;
+extern uint64_t g_display_text_char_count;
+extern float    g_display_text_x_offset;
+extern uint64_t g_cursorPos;
+
+const wchar_t * GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data, bool * reinit)
+{
+    SetCurrentContext((ImGuiContext*)imgui_context);
+    ImGuiWindow* window = GetCurrentWindow();
+    if (window->SkipItems)
+        return 0;
+
+    // NOTE(Constantine): Overriding key presses in Dear ImGui.
+    bool dearImGuiOverrideTabIsPressed            = false;
+    bool dearImGuiOverrideCtrlShiftSlashIsPressed = false;
+
+    ImGuiContext& g = *GImGui;
+    ImGuiIO& io = g.IO;
+    const ImGuiStyle& style = g.Style;
+
+    const bool RENDER_SELECTION_WHEN_INACTIVE = false;
+    const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
+    const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0;
+    const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
+    const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
+    const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0;
+    if (is_resizable)
+        IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag!
+
+    if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
+        BeginGroup();
+    const ImGuiID id = window->GetID(label);
+    const ImVec2 label_size = CalcTextSize(label, NULL, true);
+    const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
+    const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y);
+
+    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
+    const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size);
+
+    ImGuiWindow* draw_window = window;
+    ImVec2 inner_size = frame_size;
+    if (is_multiline)
+    {
+        if (!ItemAdd(total_bb, id, &frame_bb))
+        {
+            ItemSize(total_bb, style.FramePadding.y);
+            EndGroup();
+            return 0;
+        }
+
+        // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug.
+        PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
+        PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
+        PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
+        PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
+        bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding);
+        PopStyleVar(3);
+        PopStyleColor();
+        if (!child_visible)
+        {
+            EndChild();
+            EndGroup();
+            return 0;
+        }
+        draw_window = g.CurrentWindow; // Child window
+        draw_window->DC.NavLayerActiveMaskNext |= draw_window->DC.NavLayerCurrentMask; // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it.
+        inner_size.x -= draw_window->ScrollbarSizes.x;
+    }
+    else
+    {
+        ItemSize(total_bb, style.FramePadding.y);
+        if (!ItemAdd(total_bb, id, &frame_bb))
+            return 0;
+    }
+    const bool hovered = ItemHoverable(frame_bb, id);
+    if (hovered)
+        g.MouseCursor = ImGuiMouseCursor_TextInput;
+
+    // We are only allowed to access the state if we are already the active widget.
+    ImGuiInputTextState* state = GetInputTextState(id);
+
+    const bool focus_requested = FocusableItemRegister(window, id);
+    const bool focus_requested_by_code = focus_requested && (g.FocusRequestCurrWindow == window && g.FocusRequestCurrCounterRegular == window->DC.FocusCounterRegular);
+    const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
+
+    const bool user_clicked = hovered && io.MouseClicked[0];
+    const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
+    const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
+    const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
+
+    bool clear_active_id = false;
+    bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
+
+    const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start);
+    const bool init_state = (init_make_active || user_scroll_active || reinit[0]);
+    if (init_state && g.ActiveId != id)
+    {
+        reinit[0] = false;
+
+        // Access state even if we don't own it yet.
+        state = &g.InputTextState;
+        state->CursorAnimReset();
+
+        // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
+        // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
+        const int buf_len = (int)strlen(buf);
+        state->InitialTextA.resize(buf_len + 1);    // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
+        memcpy(state->InitialTextA.Data, buf, buf_len + 1);
+
+        // Start edition
+        const char* buf_end = NULL;
+        state->TextW.resize(buf_size + 1);          // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string.
+        state->TextA.resize(0);
+        state->TextAIsValid = false;                // TextA is not valid yet (we will display buf until then)
+        state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
+        state->CurLenA = (int)(buf_end - buf);      // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
+
+        // Preserve cursor position and undo/redo stack if we come back to same widget
+        // FIXME: For non-readonly widgets we might be able to require that TextAIsValid && TextA == buf ? (untested) and discard undo stack if user buffer has changed.
+        const bool recycle_state = (state->ID == id);
+        if (recycle_state)
+        {
+            // Recycle existing cursor/selection/undo stack but clamp position
+            // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
+            state->CursorClamp();
+        }
+        else
+        {
+            state->ID = id;
+            state->ScrollX = 0.0f;
+            stb_textedit_initialize_state(&state->Stb, !is_multiline);
+            if (!is_multiline && focus_requested_by_code)
+                select_all = true;
+        }
+        if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
+            state->Stb.insert_mode = 1;
+        if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
+            select_all = true;
+    }
+
+    if (g.ActiveId != id && init_make_active)
+    {
+        IM_ASSERT(state && state->ID == id);
+        SetActiveID(id, window);
+        SetFocusID(id, window);
+        FocusWindow(window);
+
+        // Declare our inputs
+        IM_ASSERT(ImGuiNavInput_COUNT < 32);
+        g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
+        if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory))
+            g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
+        g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);
+        g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End);
+        if (is_multiline)
+            g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); // FIXME-NAV: Page up/down actually not supported yet by widget, but claim them ahead.
+        if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput))  // Disable keyboard tabbing out as we will use the \t character.
+            g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab);
+    }
+
+    // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function)
+    if (g.ActiveId == id && state == NULL)
+        ClearActiveID();
+
+    // Release focus when we click outside
+    if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560
+        clear_active_id = true;
+
+    bool render_cursor = true;
+    bool render_selection = true;
+    // NOTE(Constantine): Text editing.
+    profileBegin("Text editing");
+    {
+      // Process mouse inputs and character inputs
+      int backup_current_text_length = 0;
+      if (g.ActiveId == id)
+      {
+          IM_ASSERT(state != NULL);
+          backup_current_text_length = state->CurLenA;
+          state->BufCapacityA = buf_size;
+          state->UserFlags = flags;
+          state->UserCallback = callback;
+          state->UserCallbackData = callback_user_data;
+
+          // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
+          // Down the line we should have a cleaner library-wide concept of Selected vs Active.
+          g.ActiveIdAllowOverlap = !io.MouseDown[0];
+          g.WantTextInputNextFrame = 1;
+
+          // Edit in progress
+          const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
+          const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
+
+          const bool is_osx = io.ConfigMacOSXBehaviors;
+          if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0]))
+          {
+              state->SelectAll();
+              state->SelectedAllMouseLock = true;
+          }
+          else if (hovered && is_osx && io.MouseDoubleClicked[0])
+          {
+              // Double-click select a word only, OS X style (by simulating keystrokes)
+              state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
+              state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
+          }
+          else if (io.MouseClicked[0] && !state->SelectedAllMouseLock && !io.KeyShift)
+          {
+              if (hovered)
+              {
+                  stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
+                  state->CursorAnimReset();
+              }
+          }
+          else if (io.MouseDown[0] && !state->SelectedAllMouseLock && ((io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) || io.KeyShift))
+          {
+              stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);
+              state->CursorAnimReset();
+              state->CursorFollow = true;
+          }
+          if (state->SelectedAllMouseLock && !io.MouseDown[0])
+              state->SelectedAllMouseLock = false;
+
+          // It is ill-defined whether the back-end needs to send a \t character when pressing the TAB keys.
+          // Win32 and GLFW naturally do it but not SDL.
+          const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
+          if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !is_readonly)
+          {
+              // NOTE(Constantine): Overriding TAB presses in Dear ImGui.
+              dearImGuiOverrideTabIsPressed = true;
+          }
+          if (io.KeyCtrl && io.KeyShift && IsKeyPressedMap(ImGuiKey_C))
+          {
+              // NOTE(Constantine): Overriding Ctrl + Shift + C presses in Dear ImGui.
+              dearImGuiOverrideCtrlShiftSlashIsPressed = true;
+          }
+
+          // Process regular text input (before we check for Return because using some IME will effectively send a Return?)
+          // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters.
+          if (io.InputQueueCharacters.Size > 0)
+          {
+              if (!ignore_char_inputs && !is_readonly && !user_nav_input_start)
+                  for (int n = 0; n < io.InputQueueCharacters.Size; n++)
+                  {
+                      // Insert character if they pass filtering
+                      unsigned int c = (unsigned int)io.InputQueueCharacters[n];
+                      if (c == '\t' && io.KeyShift)
+                          continue;
+                      if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) {
+                          state->OnKeyPressed((int)c);
+                          g_display_text_char_count += 1;
+                      }
+                  }
+
+              // Consume characters
+              io.InputQueueCharacters.resize(0);
+          }
+      }
+
+      // NOTE(Constantine): Overriding key presses in Dear ImGui.
+      if (dearImGuiOverrideTabIsPressed == true || dearImGuiOverrideCtrlShiftSlashIsPressed == true) {
+        bool hasSelection = state->HasSelection();
+        bool skipPasting  = false;
+
+        // Backup selection positions
+        int bakSelectStart = state->Stb.select_start;
+        int bakSelectEnd   = state->Stb.select_end;
+
+        int * bakSelectMin = bakSelectStart < bakSelectEnd ? &bakSelectStart : &bakSelectEnd;
+        int * bakSelectMax = bakSelectEnd > bakSelectStart ? &bakSelectEnd : &bakSelectStart;
+
+        bool restoreCursorMinPos = false;
+        if (state->Stb.cursor == bakSelectMin[0]) {
+          restoreCursorMinPos = true;
+        }
+
+        // Copy selection
+        char * clipboard_data = NULL;
+        if (hasSelection == true) {
+          // Copy-pasted Dear ImGui code
+          const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
+          const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
+          const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
+          clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));
+          ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
+        }
+
+        // Xform the selection
+        std::string clipboardString;
+        if (hasSelection == true) {
+          clipboardString = clipboard_data;
+          MemFree(clipboard_data);
+          clipboard_data = NULL;
+        }
+        {
+          bool holdingShift = io.KeyShift;
+
+          if (dearImGuiOverrideCtrlShiftSlashIsPressed == true) {
+            if (hasSelection == true) {
+              size_t posPrev = 0;
+              size_t pos     = 0;
+              while (pos < clipboardString.size()) {
+                char c = clipboardString[pos];
+                if (c == 0) {
+                  break;
+                }
+                if (c != ' ') {
+                  break;
+                }
+                posPrev += 1;
+                pos     += 1;
+              }
+              if ((pos + 1) < clipboardString.size() && clipboardString[pos + 0] == '/' && clipboardString[pos + 1] == '/') {
+                clipboardString.erase(pos, 2);
+                bakSelectMax[0] -= 2;
+                while (true) {
+                  pos = clipboardString.find("\n", posPrev);
+                  if (pos == std::string::npos) {
+                    break;
+                  }
+                  pos += 1;
+                  while ((pos + 1) < clipboardString.size()) {
+                    char c0 = clipboardString[pos + 0];
+                    char c1 = clipboardString[pos + 1];
+                    if (c0 == 0 || c1 == 0) {
+                      break;
+                    }
+                    if ((c0 != '/' && c0 != ' ') || (c1 != '/' && c1 != ' ')) {
+                      break;
+                    }
+                    if (c0 == '/' && c1 == '/') {
+                      clipboardString.erase(pos, 2);
+                      bakSelectMax[0] -= 2;
+                      break;
+                    }
+                    pos += 1;
+                  }
+                  posPrev = pos;
+                }
+              } else {
+                clipboardString.insert(pos, "//");
+                posPrev += std::string("//").size();
+                pos     += std::string("//").size();
+                bakSelectMax[0] += 2;
+                do {
+                  pos = clipboardString.find("\n", posPrev);
+                  if (pos != std::string::npos) {
+                    pos += std::string("\n").size();
+                    while (clipboardString[pos] == ' ' || clipboardString[pos] == '\n') {
+                      pos += 1;
+                    }
+                    if (clipboardString[pos] != 0) {
+                      clipboardString.insert(pos, "//");
+                      pos += std::string("//").size();
+                      bakSelectMax[0] += 2;
+                    }
+                  }
+                  posPrev = pos;
+                } while (pos != std::string::npos);
+              }
+            }
+          } else if (dearImGuiOverrideTabIsPressed == true && holdingShift == false) {
+            if (hasSelection == false) {
+              clipboardString += "  ";
+              bakSelectMin[0] += 2;
+              bakSelectMax[0] += 2;
+            } else {
+              if (clipboardString.find("\n", 0) == std::string::npos) {
+                // NOTE(Constantine): When Tab is pressed on a selection on a single line, it replaces the selection with 2 spaces and exits the selection mode.
+                stb_textedit_cut(state, &state->Stb);
+                clipboardString     = "  ";
+                restoreCursorMinPos = false;
+                bakSelectMin[0]     = state->Stb.cursor;
+                bakSelectMax[0]     = state->Stb.cursor;
+              } else {
+                clipboardString.insert(0, "  ");
+                bakSelectMax[0] += 2;
+
+                size_t posPrev = 0;
+                size_t pos     = std::string::npos;
+                do {
+                  pos = clipboardString.find("\n", posPrev);
+                  if (pos != std::string::npos) {
+                    if ((pos + 1) == (bakSelectMax[0] - bakSelectMin[0])) {
+                      pos = std::string::npos;
+                    } else {
+                      clipboardString.replace(pos, std::string("\n").size(), "\n  ");
+                      pos += std::string("\n  ").size();
+                      bakSelectMax[0] += 2;
+                    }
+                  }
+                  posPrev = pos;
+                } while (pos != std::string::npos);
+              }
+            }
+          } else if (dearImGuiOverrideTabIsPressed == true && holdingShift == true && clipboardString.size() == 1 && clipboardString[0] == ' ') {
+            // NOTE(Constantine): Special case for a selection of 1 space character.
+            stb_textedit_cut(state, &state->Stb);
+            bakSelectMax[0] -= 1;
+            skipPasting = true;
+          } else if (dearImGuiOverrideTabIsPressed == true && holdingShift == true && clipboardString.size() == 2 && clipboardString[0] == ' ' && clipboardString[1] == ' ') {
+            // NOTE(Constantine): Special case for a selection of 1 space character.
+            stb_textedit_cut(state, &state->Stb);
+            bakSelectMax[0] -= 2;
+            skipPasting = true;
+          } else if (dearImGuiOverrideTabIsPressed == true && holdingShift == true) {
+            if (hasSelection == true) {
+              if (clipboardString.size() > 2) {
+                if (clipboardString[0] == ' ' && clipboardString[1] == ' ') {
+                  clipboardString.erase(0, 2);
+                  bakSelectMax[0] -= 2;
+                }
+              }
+
+              size_t posPrev = 0;
+              size_t pos     = std::string::npos;
+              do {
+                pos = clipboardString.find("\n  ", posPrev);
+                if (pos != std::string::npos) {
+                  if ((pos + 1) == bakSelectMax[0]) {
+                    pos = std::string::npos;
+                  } else {
+                    clipboardString.replace(pos, std::string("\n  ").size(), "\n");
+                    pos += std::string("\n").size();
+                    bakSelectMax[0] -= 2;
+                  }
+                }
+                posPrev = pos;
+              } while (pos != std::string::npos);
+            }
+          }
+        }
+
+        // Paste
+        const char * clipboard = clipboardString.c_str();
+        if (skipPasting == false) {
+          // Copy-pasted Dear ImGui code
+          const int clipboard_len = (int)strlen(clipboard);
+          ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar));
+          int clipboard_filtered_len = 0;
+          for (const char* s = clipboard; *s; )
+          {
+              unsigned int c;
+              s += ImTextCharFromUtf8(&c, s, NULL);
+              if (c == 0)
+                  break;
+              if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data))
+                  continue;
+              clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
+          }
+          clipboard_filtered[clipboard_filtered_len] = 0;
+          if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
+          {
+              stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len);
+              state->CursorFollow = true;
+              g_display_text_char_count += clipboard_len + 1;
+          }
+          MemFree(clipboard_filtered);
+        }
+
+        // Restore cursor and selection positions
+        if (restoreCursorMinPos == true) {
+          state->Stb.cursor = bakSelectMin[0];
+        }
+        state->Stb.select_start = bakSelectStart;
+        state->Stb.select_end   = bakSelectEnd;
+      }
+      // NOTE(Constantine): Go to line logic.
+      if (state != NULL && g_dearImGuiGoToLine > 0 && flags & ImGuiInputTextFlags_AllowTabInput) {
+        int goToLine = g_dearImGuiGoToLine;
+        for (size_t i = 0, currentLine = 1; ; i += 1) {
+          if (goToLine == currentLine) {
+            state->Stb.cursor       = i;
+            state->Stb.select_start = i;
+            state->Stb.select_end   = i;
+            g_dearImGuiGoToLine     = 0;
+            state->CursorFollow     = true;
+            break;
+          }
+          char c = (char)state->TextW.Data[i];
+          if (c == 0) {
+            break;
+          }
+          if (c == '\n') {
+            currentLine += 1;
+          }
+        }
+      }
+      // NOTE(Constantine): Go to char position logic.
+      if (state != NULL && g_dearImGuiGoToCharPosition != -1) {
+        state->Stb.cursor                         = g_dearImGuiGoToCharPosition;
+        state->Stb.select_start                   = g_dearImGuiGoToCharPositionSelectionStart;
+        state->Stb.select_end                     = g_dearImGuiGoToCharPositionSelectionEnd;
+        g_dearImGuiGoToCharPosition               = -1;
+        g_dearImGuiGoToCharPositionSelectionStart = -1;
+        g_dearImGuiGoToCharPositionSelectionEnd   = -1;
+        state->CursorFollow                       = true;
+      }
+
+      // Process other shortcuts/key-presses
+      bool cancel_edit = false;
+      if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
+      {
+          IM_ASSERT(state != NULL);
+          IM_ASSERT(io.KeyMods == GetMergedKeyModFlags() && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); // We rarely do this check, but if anything let's do it here.
+
+          const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
+          const bool is_osx = io.ConfigMacOSXBehaviors;
+          const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyModFlags_Super | ImGuiKeyModFlags_Shift));
+          const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl;                     // OS X style: Text editing cursor movement using Alt instead of Ctrl
+          const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt;  // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
+          const bool is_ctrl_key_only = (io.KeyMods == ImGuiKeyModFlags_Ctrl);
+          const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift);
+          const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl);
+
+          const bool is_cut   = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
+          const bool is_copy  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only  && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection());
+          const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly;
+          const bool is_undo  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable);
+          const bool is_redo  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable;
+
+          if (IsKeyPressedMap(ImGuiKey_LeftArrow))                        { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_RightArrow))                  { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline)     { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline)   { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_Home))                        { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_End))                         { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly)      { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
+          else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly)
+          {
+              if (!state->HasSelection())
+              {
+                  if (is_wordmove_key_down)
+                      state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
+                  else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl)
+                      state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
+              }
+              state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
+          }
+          else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter))
+          {
+              bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
+              if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
+              {
+                  bool enter_pressed = clear_active_id = true;
+              }
+              else if (!is_readonly)
+              {
+                  unsigned int c = '\n'; // Insert new line
+                  if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
+                      state->OnKeyPressed((int)c);
+              }
+          }
+          else if (IsKeyPressedMap(ImGuiKey_Escape))
+          {
+              clear_active_id = cancel_edit = true;
+          }
+          else if (is_undo || is_redo)
+          {
+              state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
+              state->ClearSelection();
+          }
+          else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A))
+          {
+              state->SelectAll();
+              state->CursorFollow = true;
+          }
+          else if (is_cut || is_copy)
+          {
+              // Cut, Copy
+              if (io.SetClipboardTextFn)
+              {
+                  const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
+                  const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
+                  const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
+                  char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));
+                  ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
+                  SetClipboardText(clipboard_data);
+                  MemFree(clipboard_data);
+              }
+              if (is_cut)
+              {
+                  if (!state->HasSelection())
+                      state->SelectAll();
+                  state->CursorFollow = true;
+                  stb_textedit_cut(state, &state->Stb);
+              }
+          }
+          else if (is_paste)
+          {
+              if (const char* clipboard = GetClipboardText())
+              {
+                  // Filter pasted buffer
+                  const int clipboard_len = (int)strlen(clipboard);
+                  ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar));
+                  int clipboard_filtered_len = 0;
+                  for (const char* s = clipboard; *s; )
+                  {
+                      unsigned int c;
+                      s += ImTextCharFromUtf8(&c, s, NULL);
+                      if (c == 0)
+                          break;
+                      if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data))
+                          continue;
+                      clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
+                  }
+                  clipboard_filtered[clipboard_filtered_len] = 0;
+                  if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
+                  {
+                      stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len);
+                      state->CursorFollow = true;
+                      g_display_text_char_count += clipboard_len + 1;
+                  }
+                  MemFree(clipboard_filtered);
+              }
+          }
+
+          // Update render selection flag after events have been handled, so selection highlight can be displayed during the same frame.
+          render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
+      }
+    }
+    profileEnd("Text editing");
+
+    // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
+    if (clear_active_id && g.ActiveId == id)
+        ClearActiveID();
+
+    // NOTE(Constantine):
+    int line_count = 1;
+
+    const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid;
+    const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
+
+    ImVec2 text_size(0.0f, 0.0f);
+    text_size = ImVec2(inner_size.x, line_count * g.FontSize);
+
+    const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595
+    const char* buf_display_end = NULL; // We have specialized paths below for setting the length
+
+    const int buf_display_max_length = 2 * 1024 * 1024;
+
+    ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
+    draw_pos.x -= g_display_text_x_offset;
+    //draw_pos.y -= (float)g_display_text_line_offset * g.FontSize;
+
+    if (state != 0) {
+        // Scroll
+        if (render_cursor && state->CursorFollow && g_scrollCode)
+        {
+            g_scrollCode = false;
+
+            {
+                state->ScrollX = 0.0f;
+            }
+
+            // Vertical scroll
+            if (is_multiline)
+            {
+                //float scroll_y = draw_window->Scroll.y;
+                //if (cursor_offset.y - g.FontSize < scroll_y)
+                //    scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
+                //else if (cursor_offset.y - inner_size.y >= scroll_y)
+                //    scroll_y = cursor_offset.y - inner_size.y;
+                //draw_pos.y += (draw_window->Scroll.y - scroll_y);   // Manipulate cursor pos immediately avoid a frame of lag
+                //draw_window->Scroll.y = scroll_y;
+                draw_pos.y += (draw_window->Scroll.y - ((g_codeCurrentLineNumber * g.FontSize) - (1.f * g.FontSize)));
+                draw_window->Scroll.y = ((g_codeCurrentLineNumber * g.FontSize) - (1.f * g.FontSize));
+            }
+
+            state->CursorFollow = false;
+        }
+    }
+
+    {
+        const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y);
+
+        // Draw blinking cursor
+        if (false && state != NULL && render_cursor)
+        {
+            //printf("state->Stb.cursor: %d\n", state->Stb.cursor); // NOTE(Constantine): Debug, delete later.
+            state->CursorAnim += io.DeltaTime;
+            bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
+            ImVec2 cursor_screen_pos = draw_pos;// + cursor_offset - draw_scroll;
+            { // NOTE(Constantine): Cursor X line offset.
+              ImGuiContext& g = *GImGui;
+              ImFont* font = g.Font;
+              const float line_height = g.FontSize;
+              const float scale = line_height / font->FontSize;
+              const float char_width = font->GetCharAdvance((ImWchar)L' ') * scale;
+
+              cursor_screen_pos.x += 1 * char_width;
+            }
+            cursor_screen_pos.y += 1 * g.FontSize; // NOTE(Constantine): Cursor Y line offset.
+            ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
+            if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
+                draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
+
+            // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
+            if (!is_readonly)
+            {
+                g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
+                g.PlatformImePosViewport = window->Viewport;
+            }
+        }
+    }
+    {
+        // Render selection
+        if (state != NULL) {
+            const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y);
+
+            // Render text. We currently only render selection when the widget is active or while scrolling.
+            // FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive.
+            if (render_cursor || render_selection)
+            {
+                IM_ASSERT(state != NULL);
+                if (!is_displaying_hint)
+                    buf_display_end = buf_display + state->CurLenA;
+
+                // Render text (with cursor and selection)
+                // This is going to be messy. We need to:
+                // - Display the text (this alone can be more easily clipped)
+                // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
+                // - Measure text height (for scrollbar)
+                // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
+                // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
+                const ImWchar* text_begin = state->TextW.Data;
+                ImVec2 cursor_offset, select_start_offset;
+
+                {
+                    // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
+                    const ImWchar* searches_input_ptr[2] = { NULL, NULL };
+                    int searches_result_line_no[2] = { -1000, -1000 };
+                    int searches_remaining = 0;
+                    if (render_cursor)
+                    {
+                        searches_input_ptr[0] = text_begin + state->Stb.cursor;
+                        searches_result_line_no[0] = -1;
+                        searches_remaining++;
+                    }
+                    if (render_selection)
+                    {
+                        searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
+                        searches_result_line_no[1] = -1;
+                        searches_remaining++;
+                    }
+
+                    // Iterate all lines to find our line numbers
+                    // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
+                    searches_remaining += is_multiline ? 1 : 0;
+                    int line_count = 0;
+                    //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++)  // FIXME-OPT: Could use this when wchar_t are 16-bit
+                    const ImWchar* s = text_begin;
+                    const int line_count_max = g_display_text_line_count < 100 ? 100 : g_display_text_line_count;
+                    for (int i = 0; s[i] != 0; s++) {
+                        if (s[i] == '\n')
+                        {
+                            line_count++;
+                            if (searches_result_line_no[0] == -1 && &s[i] >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
+                            if (searches_result_line_no[1] == -1 && &s[i] >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
+                            if (line_count > line_count_max) { break; }
+                        }
+                    }
+                    line_count++;
+                    if (searches_result_line_no[0] == -1)
+                        searches_result_line_no[0] = line_count;
+                    if (searches_result_line_no[1] == -1)
+                        searches_result_line_no[1] = line_count;
+
+                    // Calculate 2d position by finding the beginning of the line and measuring distance
+                    cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
+                    cursor_offset.y = searches_result_line_no[0] * g.FontSize;
+                    if (searches_result_line_no[1] >= 0)
+                    {
+                        select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
+                        select_start_offset.y = searches_result_line_no[1] * g.FontSize;
+                    }
+
+                    // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
+                    if (is_multiline)
+                        text_size = ImVec2(inner_size.x, line_count * g.FontSize);
+                }
+
+                // Scroll
+                if (render_cursor && state->CursorFollow)
+                {
+                    // Horizontal scroll in chunks of quarter width
+                    if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
+                    {
+                        const float scroll_increment_x = inner_size.x * 0.25f;
+                        if (cursor_offset.x < state->ScrollX)
+                            state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x));
+                        else if (cursor_offset.x - inner_size.x >= state->ScrollX)
+                            state->ScrollX = IM_FLOOR(cursor_offset.x - inner_size.x + scroll_increment_x);
+                    }
+                    else
+                    {
+                        state->ScrollX = 0.0f;
+                    }
+
+                    // Vertical scroll
+                    if (is_multiline)
+                    {
+                        float scroll_y = draw_window->Scroll.y;
+                        if (cursor_offset.y - g.FontSize < scroll_y)
+                            scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
+                        else if (cursor_offset.y - inner_size.y >= scroll_y)
+                            scroll_y = cursor_offset.y - inner_size.y;
+                        draw_pos.y += (draw_window->Scroll.y - scroll_y);   // Manipulate cursor pos immediately avoid a frame of lag
+                        draw_window->Scroll.y = scroll_y;
+                    }
+
+                    state->CursorFollow = false;
+                }
+
+                // Draw selection
+                const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f);
+                if (render_selection)
+                {
+                    const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
+                    const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end);
+
+                    ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
+                    float bg_offy_up = is_multiline ? 0.0f : -1.0f;    // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
+                    float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
+                    ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;
+                    for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
+                    {
+                        if (rect_pos.y > clip_rect.w + g.FontSize)
+                            break;
+                        if (rect_pos.y < clip_rect.y)
+                        {
+                            //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p);  // FIXME-OPT: Could use this when wchar_t are 16-bit
+                            //p = p ? p + 1 : text_selected_end;
+                            while (p < text_selected_end)
+                                if (*p++ == '\n')
+                                    break;
+                        }
+                        else
+                        {
+                            ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
+                            if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
+                            ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn));
+                            rect.ClipWith(clip_rect);
+                            if (rect.Overlaps(clip_rect))
+                                draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
+                        }
+                        rect_pos.x = draw_pos.x - draw_scroll.x;
+                        rect_pos.y += g.FontSize;
+                    }
+                }
+
+                // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.
+                if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
+                {
+                    ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
+                    //draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);
+                    igImDrawListAddTextW(draw_window->DrawList, g.Font, g.FontSize, draw_pos, col, (const wchar_t *)state->TextW.Data, (const wchar_t *)state->TextW.Data + g_display_text_char_count, 0.0f, NULL);
+                }
+
+                // Draw blinking cursor
+                if (render_cursor)
+                {
+                    state->CursorAnim += io.DeltaTime;
+                    bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
+                    ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll;
+                    ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
+                    if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
+                        draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
+
+                    // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
+                    if (!is_readonly)
+                    {
+                        g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
+                        g.PlatformImePosViewport = window->Viewport;
+                    }
+                }
+            }
+        }
+        else
+        {
+          if (is_multiline)
+              text_size = ImVec2(inner_size.x, g_display_text_line_count * g.FontSize); // We don't need width
+          else if (!is_displaying_hint && g.ActiveId == id)
+              buf_display_end = buf_display + state->CurLenA;
+          else if (!is_displaying_hint)
+              buf_display_end = buf_display + strlen(buf_display);
+
+          if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
+          {
+              ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
+              //draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display + 0, buf_display_end, 0.0f, NULL);
+              draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, NULL);
+          }
+        }
+    }
+
+    if (is_multiline)
+    {
+        Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
+        EndChild();
+        EndGroup();
+    }
+
+    if (is_password && !is_displaying_hint)
+        PopFont();
+
+    // Log as text
+    if (g.LogEnabled && !(is_password && !is_displaying_hint))
+        LogRenderedText(&draw_pos, buf_display, buf_display_end);
+
+    if (label_size.x > 0)
+        RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
+
+    bool value_changed = false;
+    if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))
+        MarkItemEdited(id);
+
+    IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
+
+    g_cursorPos = state == 0 ? 0 : state->Stb.cursor;
+    return state == 0 ? 0 : (const wchar_t *)state->TextW.Data;
+}
+
+static bool __GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data)
 {
+    return true;
+
     SetCurrentContext((ImGuiContext*)imgui_context);
     ImGuiWindow* window = GetCurrentWindow();
     if (window->SkipItems)
@@ -526,6 +1459,16 @@ bool GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const ch
         }
       }
     }
+    // NOTE(Constantine): Go to char position logic.
+    if (state != NULL && g_dearImGuiGoToCharPosition != -1 && flags & ImGuiInputTextFlags_AllowTabInput) {
+      state->Stb.cursor                         = g_dearImGuiGoToCharPosition;
+      state->Stb.select_start                   = g_dearImGuiGoToCharPositionSelectionStart;
+      state->Stb.select_end                     = g_dearImGuiGoToCharPositionSelectionEnd;
+      g_dearImGuiGoToCharPosition               = -1;
+      g_dearImGuiGoToCharPositionSelectionStart = -1;
+      g_dearImGuiGoToCharPositionSelectionEnd   = -1;
+      state->CursorFollow                       = true;
+    }
 
     // Process other shortcuts/key-presses
     bool cancel_edit = false;
@@ -721,7 +1664,7 @@ bool GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const ch
                     memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData));
                     callback_data.EventFlag = event_flag;
                     callback_data.Flags = flags;
-                    callback_data.UserData = callback_user_data;
+                    callback_data.UserData = (void *)(ImWchar *)state->TextW.Data; // NOTE(Constantine): used to be callback_user_data, but I didn't use that, so passing stb's wide chars state->TextW.Data here directly now.
 
                     callback_data.EventKey = event_key;
                     callback_data.Buf = state->TextA.Data;
@@ -729,11 +1672,9 @@ bool GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const ch
                     callback_data.BufSize = state->BufCapacityA;
                     callback_data.BufDirty = false;
 
-                    // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
-                    ImWchar* text = state->TextW.Data;
-                    const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor);
-                    const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start);
-                    const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end);
+                    callback_data.CursorPos = state->Stb.cursor;
+                    callback_data.SelectionStart = state->Stb.select_start;
+                    callback_data.SelectionEnd = state->Stb.select_end;
 
                     // Call user code
                     callback(&callback_data);
@@ -742,9 +1683,6 @@ bool GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const ch
                     IM_ASSERT(callback_data.Buf == state->TextA.Data);  // Invalid to modify those fields
                     IM_ASSERT(callback_data.BufSize == state->BufCapacityA);
                     IM_ASSERT(callback_data.Flags == flags);
-                    if (callback_data.CursorPos != utf8_cursor_pos)            { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; }
-                    if (callback_data.SelectionStart != utf8_selection_start)  { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }
-                    if (callback_data.SelectionEnd != utf8_selection_end)      { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }
                     if (callback_data.BufDirty)
                     {
                         IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
@@ -1033,12 +1971,12 @@ bool GameScriptImGuiInputTextEx(void* imgui_context, const char* label, const ch
         return value_changed;
 }
 
-bool GameScriptImGuiInputTextMultiline(void* imgui_context, const char* label, char* buf, size_t buf_size, const void* size_ptr, unsigned flags, void* callback, void* user_data)
+const wchar_t * GameScriptImGuiInputTextMultiline(void* imgui_context, const char* label, char* buf, size_t buf_size, const void* size_ptr, unsigned flags, void* callback, void* user_data, bool * reinit)
 {
     ImVec2 size = {};
     if (size_ptr != NULL) {
       size = ((const ImVec2 *)size_ptr)[0];
     }
-    return GameScriptImGuiInputTextEx(imgui_context, label, NULL, buf, (int)buf_size, size, (ImGuiInputTextFlags)flags | ImGuiInputTextFlags_Multiline, (ImGuiInputTextCallback)callback, user_data);
+    return GameScriptImGuiInputTextEx(imgui_context, label, NULL, buf, (int)buf_size, size, (ImGuiInputTextFlags)flags | ImGuiInputTextFlags_Multiline, (ImGuiInputTextCallback)callback, user_data, reinit);
 }
 
diff --git a/source_code/gamescript_imgui_custom_input_text_multiline.h b/source_code/gamescript_imgui_custom_input_text_multiline.h
index 0f37e45..20f05c2 100644
--- a/source_code/gamescript_imgui_custom_input_text_multiline.h
+++ b/source_code/gamescript_imgui_custom_input_text_multiline.h
@@ -1,2 +1,2 @@
-bool GameScriptImGuiInputTextMultiline(void* imgui_context, const char* label, char* buf, size_t buf_size, const void* size_ptr, unsigned flags, void* callback, void* user_data);
+const wchar_t * GameScriptImGuiInputTextMultiline(void* imgui_context, const char* label, char* buf, size_t buf_size, const void* size_ptr, unsigned flags, void* callback, void* user_data, bool * reinit);
 
diff --git a/source_code/main.cpp b/source_code/main.cpp
index 9f6a4d1..ea2251d 100644
--- a/source_code/main.cpp
+++ b/source_code/main.cpp
@@ -38,16 +38,6 @@
 #include "gamescript.cpp"
 #endif
 
-#if defined(GAME_SCRIPT_NATIVE)
-#define GAME_SCRIPT_WINDOW_TITLE "Game Script Native from Dec 22, 2022 (procedural.itch.io/gamescript)"
-#elif defined(GAME_SCRIPT_MIN)
-#define GAME_SCRIPT_WINDOW_TITLE "Game Script Min from Dec 22, 2022 (procedural.itch.io/gamescript)"
-#elif defined(GAME_SCRIPT_C)
-#define GAME_SCRIPT_WINDOW_TITLE "Game Script C from Dec 22, 2022 (procedural.itch.io/gamescript)"
-#else
-#define GAME_SCRIPT_WINDOW_TITLE "Game Script from Dec 22, 2022 (procedural.itch.io/gamescript)"
-#endif
-
 #if defined(_WIN32) && defined(GAME_SCRIPT_NATIVE)
 #define GSN_WIN_EXPORT __declspec(dllexport)
 #else
@@ -183,6 +173,9 @@ GSN_WIN_EXPORT float                                                    gDragAnd
 GSN_WIN_EXPORT std::vector<std::string>                                 gDragAndDropFilepaths;
 GSN_WIN_EXPORT uint64_t                                                 g_codeCurrentLineNumber                                 = 1;
 GSN_WIN_EXPORT int                                                      g_dearImGuiGoToLine                                     = 0;
+GSN_WIN_EXPORT int                                                      g_dearImGuiGoToCharPosition                             = 0;
+GSN_WIN_EXPORT int                                                      g_dearImGuiGoToCharPositionSelectionStart               = 0;
+GSN_WIN_EXPORT int                                                      g_dearImGuiGoToCharPositionSelectionEnd                 = 0;
 #if defined(GAME_SCRIPT_NATIVE)
 GSN_WIN_EXPORT void *                                                   libgame                                                 = 0;
 GSN_WIN_EXPORT void *                                                   libthread2                                              = 0;
@@ -201,6 +194,28 @@ static int  g_previousWindowPosX        = 0;
 static int  g_previousWindowPosY        = 0;
 static int  g_previousWindowWidth       = 0;
 static int  g_previousWindowHeight      = 0;
+static bool g_reinit_script             = false;
+static const wchar_t * g_code_wchar_data         = 0;
+uint64_t               g_display_text_line_count = 0;
+uint64_t               g_display_text_line_count_max = 100;
+uint64_t               g_display_text_char_count = 0;
+float                  g_display_text_x_offset   = 0;
+uint64_t               g_cursorPos               = 0;
+bool                   g_scrollCode              = false;
+static bool            g_isCodeEditorFocused         = false;
+static bool            g_isCodeEditorFocusedPrevious = false;
+
+#ifdef _WIN32
+static std::string g_currentlyOpenedFile          = "C:\\MainCppIDE\\main.cpp";
+static std::string g_currentlyOpenedFilenameStore = "C:\\MainCppIDE\\maincppide_current_filename.txt";
+static std::string g_autocompleteFilenameCpp      = "C:\\MainCppIDE\\maincppide_autocomplete.cpp";
+static std::string g_autocompleteFilenameScript   = "C:\\MainCppIDE\\maincppide_autocomplete.bat";
+#else
+static std::string g_currentlyOpenedFile          = "main.cpp";
+static std::string g_currentlyOpenedFilenameStore;
+static std::string g_autocompleteFilenameCpp      = "maincppide_autocomplete.cpp";
+static std::string g_autocompleteFilenameScript   = "maincppide_autocomplete.sh";
+#endif
 
 #if defined(GAME_SCRIPT_C)
 void tccMessageCallback(void * opaque, const char * msg) {
@@ -355,36 +370,143 @@ static std::vector<float> rayTriangleIntersection(float rayOriginX, float rayOri
   }
 }
 
+static void f1CommandOptionsLoad(std::string filename) {
+  std::string filepath = filename;
+
+  std::ostringstream ss;
+  ss << std::ifstream(filepath).rdbuf();
+  gF1CommandOptions = ss.str();
+
+  gF1CommandOptions.resize(gF1CommandOptions.size() + 1);
+}
+
 static void f1CommandOptionsSave(std::string filename) {
-  std::string filepath = gCurrentExeDir;
-  filepath += filename;
+  std::string filepath = filename;
 
   std::ofstream fs(filepath, std::ofstream::out);
   fs << gF1CommandOptions.c_str();
   fs.close();
 }
 
-static void scriptSave(std::string filename) {
-  std::string filepath = gCurrentExeDir;
-  filepath += filename;
+#include <codecvt> // For std::wstring_convert
 
-  std::ofstream fs(filepath, std::ofstream::out);
-  fs << gApeCodeChars.c_str();
-  if (gApeCodeChars != "") {
-    if (gApeCodeChars.back() != '\n') {
-      fs << "\n"; // NOTE(Constantine): This is here for a reason: Dear ImGui deletes last character at the beginning of script editing for some reason.
+uint64_t CalcCodeLineAndCharCounts(const char * s, bool updateLineCount) {
+  uint64_t previousLineCount = g_display_text_line_count;
+  g_display_text_line_count = 1;
+  g_display_text_char_count = 0;
+  for (int64_t i = 0; ; i++) {
+    g_display_text_char_count += 1;
+    char c = s[i];
+    if (c == 0) {
+      if (i == g_cursorPos) {
+        g_codeCurrentLineNumber = g_display_text_line_count;
+      }
+      break;
+    }
+    if (i == g_cursorPos) {
+      g_codeCurrentLineNumber = g_display_text_line_count;
+    }
+    if (c == '\n') {
+      g_display_text_line_count += 1;
     }
   }
-  fs.close();
+  uint64_t display_text_line_count_total = g_display_text_line_count;
+  if (updateLineCount == false) {
+    g_display_text_line_count = previousLineCount;
+  }
+  return display_text_line_count_total;
+}
+
+uint64_t CalcCodeLineAndCharCountsW(const wchar_t * s, bool updateLineCount) {
+  uint64_t previousLineCount = g_display_text_line_count;
+  g_display_text_line_count = 1;
+  g_display_text_char_count = 0;
+  for (int64_t i = 0; ; i++) {
+    g_display_text_char_count += 1;
+    wchar_t c = s[i];
+    if (c == 0) {
+      if (i == g_cursorPos) {
+        g_codeCurrentLineNumber = g_display_text_line_count;
+      }
+      break;
+    }
+    if (i == g_cursorPos) {
+      g_codeCurrentLineNumber = g_display_text_line_count;
+    }
+    if (c == L'\n') {
+      g_display_text_line_count += 1;
+    }
+  }
+  uint64_t display_text_line_count_total = g_display_text_line_count;
+  if (updateLineCount == false) {
+    g_display_text_line_count = previousLineCount;
+  }
+  return display_text_line_count_total;
+}
+
+static void scriptSave(std::string filename) {
+  std::string filepath = filename;
+
+  if (g_code_wchar_data != 0) {
+    uint64_t totalLineCount = CalcCodeLineAndCharCountsW(g_code_wchar_data, false);
+    g_display_text_line_count_max = totalLineCount > 100 ? totalLineCount : 100;
+
+    std::wstring utf16str = g_code_wchar_data;
+    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
+    std::string utf8str = conv.to_bytes(utf16str);
+
+    std::ofstream fs(filepath, std::ofstream::out);
+    fs << utf8str.c_str();
+    fs.close();
+  } else {
+    uint64_t totalLineCount = CalcCodeLineAndCharCounts(gApeCodeChars.c_str(), false);
+    g_display_text_line_count_max = totalLineCount > 100 ? totalLineCount : 100;
+
+    std::ofstream fs(filepath, std::ofstream::out);
+    fs << gApeCodeChars.c_str();
+    fs.close();
+  }
+
+  f1CommandOptionsLoad("build_parameters.txt");
 }
 
 static void scriptLoad(std::string filename) {
-  std::string filepath = gCurrentExeDir;
-  filepath += filename;
+  {
+    std::string name;
+
+    for (size_t i = 0, count = filename.size(); i < count; i += 1) {
+      if (filename[i] == '\\' || filename[i] == '/') {
+        name.clear();
+      } else {
+        name += filename[i];
+      }
+    }
+
+    std::string title;
+    title += name;
+    title += " | ";
+    title += filename;
+    redFSetWindowTitle(title.c_str());
+
+    if (!g_currentlyOpenedFilenameStore.empty()) {
+      std::ofstream fs(g_currentlyOpenedFilenameStore.c_str(), std::ofstream::out);
+      fs << filename.c_str();
+      fs.close();
+    }
+
+    g_reinit_script = true;
+  }
+
+  std::string filepath = filename;
 
   std::ostringstream ss;
   ss << std::ifstream(filepath).rdbuf();
   gApeCodeChars = ss.str();
+
+  gApeCodeChars.resize(gApeCodeChars.size() + 1);
+
+  CalcCodeLineAndCharCounts(gApeCodeChars.c_str(), true);
+  g_display_text_line_count_max = g_display_text_line_count > 100 ? g_display_text_line_count : 100;
 }
 
 static void apeScriptRerun(RedFBool32 startupRerun) {
@@ -748,7 +870,7 @@ static void apeScriptRerun(RedFBool32 startupRerun) {
 
   }
   if (startupRerun == 0) {
-    scriptSave("autosave.script");
+    scriptSave(g_currentlyOpenedFile);
   }
   free(gApeCodeCharsCurrentlyRunning);
   if (gReadScriptFromDataGameDotScript == 0) {
@@ -927,7 +1049,6 @@ static void mape_execute(int threadIndex, void * ape, const char * code) {
 #endif
     std::string source = code;
     fs << source;
-    fs << "\n";
     fs.close();
   }
   profileEnd("save .cpp files");
@@ -993,25 +1114,60 @@ static void mape_execute(int threadIndex, void * ape, const char * code) {
 
 #endif // #if defined(GAME_SCRIPT_NATIVE)
 
+static bool ImGuiIsAnyKeyPressed() {
+  ImGuiIO * io = igGetIO();
+  for (int i = 0; i < 512; i += 1) {
+    if (io->KeysDown[i] == true) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static void UpdateCurrentLineNumber(uint64_t cursorPos) {
+  g_codeCurrentLineNumber = 1;
+  for (uint64_t i = 0; i < cursorPos; i += 1) {
+    ImWchar c = g_code_wchar_data[i];
+    if (c == L'\n') {
+      g_codeCurrentLineNumber += 1;
+    }
+  }
+}
+
+static void GoToLineAndUpdateCurrentLineNumber(uint64_t destinationLineNumber) {
+  g_codeCurrentLineNumber = 1;
+  for (uint64_t i = 0; ; i += 1) {
+    ImWchar c = gApeCodeChars[i];
+    if (c == 0) {
+      break;
+    }
+    if (c == L'\n') {
+      g_codeCurrentLineNumber += 1;
+      if (g_codeCurrentLineNumber == destinationLineNumber) {
+        break;
+      }
+    }
+  }
+}
+
 static int guiCodeEditorCallback(ImGuiInputTextCallbackData * data) {
+  //ImWchar * wchars = (ImWchar *)(void *)data->UserData;
+
   if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
     gApeCodeChars.resize(data->BufSize);
     data->Buf = &gApeCodeChars[0];
   }
   // NOTE(Constantine): Compute current line number.
-  {
-    g_codeCurrentLineNumber = 1;
+  if (ImGuiIsAnyKeyPressed() == false) {
     if (gApeCodeChars.size() > 0) {
       uint64_t cursorPos = data->CursorPos;
       if (cursorPos > (gApeCodeChars.size() - 1)) {
         cursorPos = gApeCodeChars.size() - 1;
       }
-      for (uint64_t i = 0; i < cursorPos; i += 1) {
-        char c = gApeCodeChars[i];
-        if (c == '\n') {
-          g_codeCurrentLineNumber += 1;
-        }
+      if (cursorPos != g_cursorPos) { // Recalc the line number then.
+        UpdateCurrentLineNumber(cursorPos);
       }
+      g_cursorPos = cursorPos;
     }
   }
   return 0;
@@ -1041,15 +1197,13 @@ static int guiMemoryViewerIntepretBytesCallback(ImGuiInputTextCallbackData * dat
   return 0;
 }
 
+std::string g_f1FileToRun;
+
 static void threadF1Procedure(void) {
   std::string scriptpath = "\"";
   std::string exedir = gCurrentExeDir;
   scriptpath += exedir;
-#if defined(_WIN32)
-  scriptpath += "f1.bat";
-#else
-  scriptpath += "f1.sh";
-#endif
+  scriptpath += g_f1FileToRun;
   scriptpath += "\"";
   char * output = 0;
   redFSystem(scriptpath.c_str(), &output, 0);
@@ -1731,7 +1885,7 @@ void gsglTexImage2D(unsigned target, int level, int internalformat, int width, i
 
 void RebuildFont(float scale) {
   // NOTE(Constantine): Rebuild Dear ImGui font atlas.
-  const int fontSize = 26 * scale;
+  const int fontSize = 24 * scale;
 
   ImGuiIO * io = igGetIO();
   ImFontAtlas_Clear(io->Fonts);
@@ -1766,10 +1920,241 @@ void RebuildFont(float scale) {
   ImFontAtlas_SetTexID(io->Fonts, (ImTextureID)(uint64_t)fontTextureId);
 }
 
+static int g_saveBuildParametersOnce = 0;
+
+static int guiBuildParametersEditorCallback(ImGuiInputTextCallbackData * data) {
+  if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
+    g_saveBuildParametersOnce = 1;
+    gF1CommandOptions.resize(data->BufSize);
+    data->Buf = &gF1CommandOptions[0];
+  }
+  return 0;
+}
+
+static std::string g_CtrlFTextField;
+
+static int guiCtrlFTextFieldCallback(ImGuiInputTextCallbackData * data) {
+  if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
+    g_CtrlFTextField.resize(data->BufSize);
+    data->Buf = &g_CtrlFTextField[0];
+  }
+  return 0;
+}
+
+static bool WcharIsAsciiLetterOrNumberOrUnderscore(ImWchar wchar) {
+  if (
+    wchar == L'_' ||
+    wchar == L'a' ||
+    wchar == L'b' ||
+    wchar == L'c' ||
+    wchar == L'd' ||
+    wchar == L'e' ||
+    wchar == L'f' ||
+    wchar == L'g' ||
+    wchar == L'h' ||
+    wchar == L'i' ||
+    wchar == L'j' ||
+    wchar == L'k' ||
+    wchar == L'l' ||
+    wchar == L'm' ||
+    wchar == L'n' ||
+    wchar == L'o' ||
+    wchar == L'p' ||
+    wchar == L'q' ||
+    wchar == L'r' ||
+    wchar == L's' ||
+    wchar == L't' ||
+    wchar == L'u' ||
+    wchar == L'v' ||
+    wchar == L'w' ||
+    wchar == L'x' ||
+    wchar == L'y' ||
+    wchar == L'z' ||
+    wchar == L'A' ||
+    wchar == L'B' ||
+    wchar == L'C' ||
+    wchar == L'D' ||
+    wchar == L'E' ||
+    wchar == L'F' ||
+    wchar == L'G' ||
+    wchar == L'H' ||
+    wchar == L'I' ||
+    wchar == L'J' ||
+    wchar == L'K' ||
+    wchar == L'L' ||
+    wchar == L'M' ||
+    wchar == L'N' ||
+    wchar == L'O' ||
+    wchar == L'P' ||
+    wchar == L'Q' ||
+    wchar == L'R' ||
+    wchar == L'S' ||
+    wchar == L'T' ||
+    wchar == L'U' ||
+    wchar == L'V' ||
+    wchar == L'W' ||
+    wchar == L'X' ||
+    wchar == L'Y' ||
+    wchar == L'Z' ||
+    wchar == L'0' ||
+    wchar == L'1' ||
+    wchar == L'2' ||
+    wchar == L'3' ||
+    wchar == L'4' ||
+    wchar == L'5' ||
+    wchar == L'6' ||
+    wchar == L'7' ||
+    wchar == L'8' ||
+    wchar == L'9'
+  )
+  {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+typedef struct FoundCode {
+  uint64_t selectionStart;
+  uint64_t selectionEnd;
+} FoundCode;
+
+static FoundCode FindCode(std::wstring find, int plusOrMinusOneFindDirection) {
+  uint64_t        cursorPos = g_cursorPos;
+  const wchar_t * wchars    = g_code_wchar_data;
+
+  FoundCode found = {};
+  found.selectionStart = -1;
+  found.selectionEnd   = -1;
+
+  if (wchars == 0) {
+    return found;
+  }
+
+  std::wstring token;
+  for (uint64_t i = cursorPos + (plusOrMinusOneFindDirection == -1 ? -1 : 0); ; i += plusOrMinusOneFindDirection) {
+    wchar_t wchar = 0;
+    if (i != (uint64_t)-1) {
+      //printf("i: %zu\n", i);//DEBUG
+      wchar = wchars[i];
+    } else {
+      i = 0;
+    }
+
+    // NOTE(Constantine): a special case for last the token in the file when searching backwards.
+    if (plusOrMinusOneFindDirection == -1 && (wchar == 0 || wchar == -1)) {
+      i += plusOrMinusOneFindDirection;
+      wchar = wchars[i];
+    }
+    //printf("wchar: %wc\n", wchar);//DEBUG
+
+    if (WcharIsAsciiLetterOrNumberOrUnderscore(wchar) == true) {
+      token += wchar;
+    } else {
+      if (token.size() > 0) {
+        if (plusOrMinusOneFindDirection == -1) {
+          std::reverse(token.begin(), token.end());
+        }
+        //printf("token: %ws, find: %ws\n", token.c_str(), find.c_str());//DEBUG
+        if (token.rfind(find, 0) == 0) { // https://stackoverflow.com/a/40441240
+          //printf("Passed!\n");//DEBUG
+          if (plusOrMinusOneFindDirection == -1) {
+            found.selectionStart = (i + 1);
+            found.selectionEnd   = (i + 1) + find.size();
+            //printf("found.selectionStart: %zu, found.selectionEnd: %zu\n", found.selectionStart, found.selectionEnd);//DEBUG
+          } else {
+            found.selectionStart = (i - token.size());
+            found.selectionEnd   = (i - token.size()) + find.size();
+          }
+          break;
+        }
+        token.clear();
+      }
+    }
+
+    if (wchar == 0 || wchar == -1) {
+      break;
+    }
+  }
+
+  return found;
+}
+
+static void CommandFindCodeNext() {
+  std::wstring find = std::wstring(g_CtrlFTextField.begin(), g_CtrlFTextField.end());
+  // NOTE(Constantine): Resize the find string to the first null terminator (not including it).
+  if (find.size() > 0) {
+    uint64_t newSize = 0;
+    for (size_t i = 0, count = find.size(); i < count; i += 1) {
+      if (find[i] == 0) {
+        break;
+      }
+      newSize += 1;
+    }
+    find.resize(newSize);
+  }
+  if (find.size() == 0) {
+    return;
+  }
+  FoundCode found = FindCode(find, 1);
+  if (found.selectionStart != -1 && found.selectionEnd != -1) {
+    g_cursorPos                               = found.selectionEnd;
+    g_dearImGuiGoToCharPosition               = found.selectionEnd;
+    g_dearImGuiGoToCharPositionSelectionStart = found.selectionStart;
+    g_dearImGuiGoToCharPositionSelectionEnd   = found.selectionEnd;
+    UpdateCurrentLineNumber(g_dearImGuiGoToCharPosition);
+    g_scrollCode = true;
+  }
+}
+
+static void CommandFindCodePrevious() {
+  std::wstring find = std::wstring(g_CtrlFTextField.begin(), g_CtrlFTextField.end());
+  // NOTE(Constantine): Resize the find string to the first null terminator (not including it).
+  if (find.size() > 0) {
+    uint64_t newSize = 0;
+    for (size_t i = 0, count = find.size(); i < count; i += 1) {
+      if (find[i] == 0) {
+        break;
+      }
+      newSize += 1;
+    }
+    find.resize(newSize);
+  }
+  if (find.size() == 0) {
+    return;
+  }
+  FoundCode found = FindCode(find, -1);
+  if (found.selectionStart != -1 && found.selectionEnd != -1) {
+    g_cursorPos                               = found.selectionStart;
+    g_dearImGuiGoToCharPosition               = found.selectionStart;
+    g_dearImGuiGoToCharPositionSelectionStart = found.selectionStart;
+    g_dearImGuiGoToCharPositionSelectionEnd   = found.selectionEnd;
+    UpdateCurrentLineNumber(g_dearImGuiGoToCharPosition);
+    g_scrollCode = true;
+  }
+}
+
+static int gCtrlFSetFocusOnInputField = 0;
+static int gCtrlFSetFocusOnCodeEditor = 0;
+
+void windowDragAndDropCallback(GLFWwindow * window, int count, const char ** paths) {
+  if (count <= 0) {
+    return;
+  }
+  scriptSave(g_currentlyOpenedFile);
+  g_currentlyOpenedFile = paths[0];
+  scriptLoad(g_currentlyOpenedFile);
+}
+
 void setup(void) {
   profileBegin("setup");
 
-  gF1CommandOptions.resize(4096);
+  {
+    GLFWwindow * window = (GLFWwindow *)redFGetGLFWwindowPointer();
+    glfwSetDropCallback(window, windowDragAndDropCallback);
+  }
+
+  f1CommandOptionsLoad("build_parameters.txt");
 
   gThreadF1 = redFCreateThread(1);
   if (gThreadF1 != 0) {
@@ -1807,11 +2192,10 @@ void setup(void) {
 
   srand(time(NULL));
   redFDisableArbTex(); // https://forum.openframeworks.cc/t/what-does-ofdisablearbtex-do/26377
-  redFEnableFramebufferSRGBGammaCorrection();
+  //redFEnableFramebufferSRGBGammaCorrection();
   redFEnable(0x884F); // GL_TEXTURE_CUBE_MAP_SEAMLESS, https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap
   redFClipControl(0x8CA1, 0x935F); // GL_LOWER_LEFT, GL_ZERO_TO_ONE
 
-  redFSetWindowTitle(GAME_SCRIPT_WINDOW_TITLE);
   redFSetEscapeQuitsApp(0);
   redFSetVerticalSync(1);
 
@@ -1820,11 +2204,18 @@ void setup(void) {
   ImGuiIO * io = igGetIO();
   io->FontGlobalScale = 1.0f;
   io->ConfigFlags    |= ImGuiConfigFlags_NavEnableKeyboard;
+  io->BackendFlags   |= ImGuiBackendFlags_HasMouseCursors;
+  io->ConfigWindowsMoveFromTitleBarOnly = true;
+  io->ConfigWindowsResizeFromEdges      = true;
   RebuildFont(gImguiFontGlobalScale);
   ImGuiStyle * style = igGetStyle();
+
+  igStyleColorsDark(style);
+
+#if 0
+
   style->Colors[ImGuiCol_WindowBg].w = 0.99f;
 
-#if defined(GAME_SCRIPT_NATIVE)
   // https://github.com/ocornut/imgui/issues/707#issuecomment-670976818
 
   ImVec4 bgColor;          bgColor.x          = 37/255.f; bgColor.y          = 37/255.f; bgColor.z          = 38/255.f; bgColor.w          = 0.99f;
@@ -1890,6 +2281,8 @@ void setup(void) {
   style->Colors[ImGuiCol_TabUnfocusedActive]   = panelActiveColor;
   style->Colors[ImGuiCol_TabHovered]           = panelHoverColor;
 
+#endif
+
   style->WindowRounding    = 0.0f;
   style->ChildRounding     = 0.0f;
   style->FrameRounding     = 0.0f;
@@ -1897,7 +2290,6 @@ void setup(void) {
   style->PopupRounding     = 0.0f;
   style->ScrollbarRounding = 0.0f;
   style->TabRounding       = 0.0f;
-#endif
 
   gCamera = redFCreateFirstPersonCamera(1);
   redFFirstPersonCameraSetMoveSpeed(gCamera[0], 0.25f);
@@ -1905,7 +2297,12 @@ void setup(void) {
   redFNodeSetGlobalPosition(redFFirstPersonCameraCastToNode(gCamera[0]), 0, 0, 10);
 
   apeScriptRerun(1);
-  scriptLoad("autosave.script");
+  scriptLoad(g_currentlyOpenedFile);
+
+  { // NOTE(Constantine): Focus on the code editor window by default.
+    gCtrlFSetFocusOnCodeEditor = 1;
+    CommandFindCodeNext();
+  }
 
   profileEnd("setup");
 }
@@ -1948,6 +2345,8 @@ void SetBorderlessWindowedFullscreen(int enable) {
   }
 }
 
+static int g_resizeMainCodeWindow = true;
+
 void draw(void) {
   profileBegin("draw");
   std::string thread1FrameString;
@@ -2782,6 +3181,7 @@ void draw(void) {
   if (setRerunTo0 == 1) {
     gRerun = 0;
   }
+  redFBackground(0, 0, 0, 255);
   redFDisableCulling();
   redFColorMask(1, 1, 1, 1);
   redFSetColor(255, 255, 255, 255);
@@ -3244,18 +3644,28 @@ void draw(void) {
         gF1SetNextWindowFocusOnce = 0;
         igSetNextWindowFocus();
       }
-      if (igBegin("F1", (bool *)&gF1WindowIsShownFromNowOn, 0)) {
+      if (igBegin("F5: run build script | Ctrl + Space: autocomplete code after ` character", (bool *)&gF1WindowIsShownFromNowOn, 0)) {
         ImVec2 f1WindowSize = {800, 400};
         igSetWindowSizeVec2(f1WindowSize, ImGuiCond_FirstUseEver);
         if (redFThreadIsRunning(gThreadF1[0]) == 1) {
-#if defined(_WIN32)
-          igText("f1.bat is running...");
-#else
-          igText("f1.sh is running...");
-#endif
+          std::string running;
+          running += g_f1FileToRun;
+          running += " is running...";
+          igText(running.c_str());
           igSeparator();
         }
-        igInputText("f1_options.txt", &gF1CommandOptions[0], 4096, 0, 0, 0);
+
+        if (gCtrlFSetFocusOnInputField == 1) {
+          gCtrlFSetFocusOnInputField = 0;
+          igSetKeyboardFocusHere(0);
+        }
+        igInputText("F3: find ASCII token word", &g_CtrlFTextField[0], g_CtrlFTextField.size(), ImGuiInputTextFlags_CallbackResize, (ImGuiInputTextCallback)guiCtrlFTextFieldCallback, 0);
+
+        igInputText("build_parameters.txt", &gF1CommandOptions[0], gF1CommandOptions.size(), ImGuiInputTextFlags_CallbackResize, (ImGuiInputTextCallback)guiBuildParametersEditorCallback, 0);
+        if (g_saveBuildParametersOnce == 1) {
+          g_saveBuildParametersOnce = 0;
+          f1CommandOptionsSave("build_parameters.txt");
+        }
         ImVec2 inputSize = {};
         inputSize.x = -1;
         inputSize.y = -1;
@@ -3264,7 +3674,7 @@ void draw(void) {
           igInputTextMultiline(" F1", &gThreadF1OutputText[0], gThreadF1OutputText.size(), inputSize, ImGuiInputTextFlags_ReadOnly, 0, 0);
         }
 
-        igText("Current line: %llu", g_codeCurrentLineNumber);
+        igText("Current line calc: %llu", g_codeCurrentLineNumber);
         static int goToLine = 1;
         if (igInputInt("Go to line", &goToLine, 0, 0, 0)) {
           size_t linesCount = (!gApeCodeChars.empty() && gApeCodeChars.back() != '\n') ? 1 : 0;
@@ -3282,17 +3692,38 @@ void draw(void) {
         }
         ImVec2 defaults = {};
         if (igButton("Go", defaults)) {
+          GoToLineAndUpdateCurrentLineNumber(goToLine);
           g_dearImGuiGoToLine = goToLine;
+          g_scrollCode = true;
         }
       }
       igEnd();
     }
     static int apeScriptWindowIsOpen = 1;
-    if (igBegin("Game (F3)", (bool *)&apeScriptWindowIsOpen, 0)) {
-      ImVec2 apeWindowSize = {1100, 600};
-      igSetWindowSizeVec2(apeWindowSize, ImGuiCond_FirstUseEver);
+    ImGuiIO * io = igGetIO();
+    ImVec2 v;
+    v.x = 0;
+    v.y = 0;
+    ImGuiCond cond = 0;
+    ImVec2 pivot;
+    pivot.x = 0;
+    pivot.y = 0;
+    static int g_alwaysFitCodeToWindow = 1;
+    if (g_resizeMainCodeWindow == 1 || g_alwaysFitCodeToWindow == 1) {
+      g_resizeMainCodeWindow = 0;
+
+      igSetNextWindowPos(v, cond, pivot);
+      v.x = io->DisplaySize.x;
+      v.y = io->DisplaySize.y;
+      igSetNextWindowSize(v, cond);
+    }
+    if (gCtrlFSetFocusOnCodeEditor == 1) {
+      igSetNextWindowFocus();
+    }
+    if (igBegin("Main Cpp IDE procedural.itch.io/maincppide", NULL, ImGuiWindowFlags_NoCollapse | (g_alwaysFitCodeToWindow == 0 ? 0 : (ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize)))) {
+      gF1WindowIsShownFromNowOn = gF1WindowIsShownFromNowOn == 1 ? !igIsWindowFocused(0) : false;
       ImVec2 buttonSize = {};
-      if (igButton("Rerun (F5)", buttonSize)) {
+      if (false && igButton("Rerun (F5)", buttonSize)) {
         apeScriptRerun(0);
         if (gStopScript == 1) {
           gRunScriptOnce = 2;
@@ -3301,10 +3732,25 @@ void draw(void) {
           gCurrentFrame -= 1; // NOTE(Constantine): Workaround, since the next gCurrentFrame += 1 must set it to 0.
         }
       }
-      igSameLine(0, 14);
-      igCheckbox("Run from game.script", (bool *)&gReadScriptFromDataGameDotScript);
-      igSameLine(0, 14);
-      igText("| Current frame: %lu", gCurrentFrame == (uint64_t)-1 ? 0 : gCurrentFrame);
+      igText("Current line calc: %llu | ", g_codeCurrentLineNumber);
+      igSameLine(0, 0);
+      igCheckbox("Fit code to window", (bool *)&g_alwaysFitCodeToWindow);
+      igSameLine(0, 15);
+      igText("| Current frame: %lu | F1: toggle console | F4: fit code to window | F5: build", gCurrentFrame == (uint64_t)-1 ? 0 : gCurrentFrame);
+      igSetNextItemWidth(350.f);
+      igSliderInt("Line count", (int *)&g_display_text_line_count, 0, g_display_text_line_count_max, 0);
+      igSameLine(0, 15);
+      igSetNextItemWidth(250.f);
+      igInputInt("Char count", (int *)&g_display_text_char_count, 1, 1, 0);
+      igSameLine(0, 15);
+      ImVec2 defaults = {};
+      if (igButton("Calc counts", defaults)) {
+        CalcCodeLineAndCharCountsW(g_code_wchar_data, true);
+        g_display_text_line_count_max = g_display_text_line_count > 100 ? g_display_text_line_count : 100;
+      }
+      igSameLine(0, 15);
+      igSetNextItemWidth(350.f);
+      igSliderFloat("Horizontal offset", &g_display_text_x_offset, 0, 5000, 0, 1);
       {
         if (gApeErrorCheck >= 1) {
           if (gApeErrorCheck == 1) {
@@ -3339,7 +3785,22 @@ void draw(void) {
         ImVec2 inputSize = {};
         inputSize.x = -1;
         inputSize.y = -1;
-        GameScriptImGuiInputTextMultiline((void *)igGetCurrentContext(), " Script", &gApeCodeChars[0], gApeCodeChars.size(), &inputSize, ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_CallbackResize | ImGuiInputTextFlags_CallbackAlways, (void *)guiCodeEditorCallback, 0);
+        g_code_wchar_data = GameScriptImGuiInputTextMultiline((void *)igGetCurrentContext(), g_currentlyOpenedFile.c_str(), &gApeCodeChars[0], gApeCodeChars.size() + 1, &inputSize, ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_CallbackResize | ImGuiInputTextFlags_CallbackAlways, (void *)guiCodeEditorCallback, 0, &g_reinit_script);
+        // NOTE(Constantine): There is a bug that doesn't preserve the current code edits if any other widgets such as sliders were Ctrl + Left Mouse Button clicked right after the editor was focused.
+        g_isCodeEditorFocused = igIsItemActive() || igIsItemFocused();
+        if (g_isCodeEditorFocusedPrevious == true && g_isCodeEditorFocused == false && g_code_wchar_data != 0) {
+          std::wstring utf16str = g_code_wchar_data;
+          std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
+          gApeCodeChars = conv.to_bytes(utf16str);
+
+          CalcCodeLineAndCharCounts(gApeCodeChars.c_str(), false);
+          g_display_text_line_count_max = g_display_text_line_count > 100 ? g_display_text_line_count : 100;
+        }
+        g_isCodeEditorFocusedPrevious = g_isCodeEditorFocused;
+      }
+      if (gCtrlFSetFocusOnCodeEditor == 1) {
+        gCtrlFSetFocusOnCodeEditor = 0;
+        igSetKeyboardFocusHere(-1);
       }
     }
     igEnd();
@@ -3350,7 +3811,7 @@ void draw(void) {
     static int apeMemoryViewerWindowBytesRangeLimitFirst    = 0;
     static int apeMemoryViewerWindowBytesRangeLimitCount    = 8;
     static int apeMemoryViewerWindowBytesPerRow             = 8;
-    if (igBegin("Memory viewer", (bool *)&apeMemoryViewerWindowIsOpen, 0)) {
+    if (false && igBegin("Memory viewer", (bool *)&apeMemoryViewerWindowIsOpen, 0)) {
       {
         ImVec2 pos  = {};
         ImVec2 size = {};
@@ -3713,7 +4174,7 @@ void draw(void) {
         }
       }
     }
-    igEnd();
+    //igEnd();
     redFImguiEnd(gGuiImgui[0]);
     redFPopStyle();
   }
@@ -3790,30 +4251,69 @@ static void keyPressed(RedFHandleEventParametersKey parameters) {
     g_windowIsHoldingCtrlKey = true;
   }
 
-  if (gDisableDefaultFkeys == 0) {
-    if (keycode == GLFW_KEY_F1) {
+  {
+    if (keycode == GLFW_KEY_F5) { // build
       gF1SetNextWindowFocusOnce = 1;
       if (gF1WindowIsShownFromNowOn == 0) {
         gF1WindowIsShownFromNowOn = 1;
       } else {
+        scriptSave(g_currentlyOpenedFile);
+        if (redFThreadIsRunning(gThreadF1[0]) == 0) {
+          #if defined(_WIN32)
+          g_f1FileToRun = "build.bat";
+          #else
+          g_f1FileToRun = "build.sh";
+          #endif
+          redFThreadStart(gThreadF1[0]);
+        }
+      }
+    } else if (keycode == GLFW_KEY_F1) { // toggle console
+      if (g_code_wchar_data != 0) { // NOTE(Constantine): Needed on switching widget focus.
+        std::wstring utf16str = g_code_wchar_data;
+        std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
+        gApeCodeChars = conv.to_bytes(utf16str);
+      }
+      gF1WindowIsShownFromNowOn = !gF1WindowIsShownFromNowOn;
+    } else if (g_windowIsHoldingCtrlKey && gGlfwKeyEvent[GLFW_KEY_S]) { // save
+      scriptSave(g_currentlyOpenedFile);
+    } else if (g_windowIsHoldingCtrlKey && gGlfwKeyEvent[GLFW_KEY_F]) { // find window
+      if (g_code_wchar_data != 0) { // NOTE(Constantine): Needed on switching widget focus.
+        std::wstring utf16str = g_code_wchar_data;
+        std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
+        gApeCodeChars = conv.to_bytes(utf16str);
+      }
+      gF1WindowIsShownFromNowOn  = 1;
+      gCtrlFSetFocusOnInputField = 1;
+    } else if (keycode == GLFW_KEY_F2) { // find previous
+      gCtrlFSetFocusOnCodeEditor = 1;
+      CommandFindCodePrevious();
+    } else if (keycode == GLFW_KEY_F3) { // find next
+      gCtrlFSetFocusOnCodeEditor = 1;
+      CommandFindCodeNext();
+    } else if (g_windowIsHoldingCtrlKey && gGlfwKeyEvent[GLFW_KEY_SPACE]) { // autocomplete
+      if (g_code_wchar_data != 0) { // NOTE(Constantine): Needed on switching widget focus.
+        std::wstring utf16str = g_code_wchar_data;
+        std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
+        gApeCodeChars = conv.to_bytes(utf16str);
+      }
+      gF1WindowIsShownFromNowOn = 1;
+      {
+        scriptSave(g_autocompleteFilenameCpp);
         if (redFThreadIsRunning(gThreadF1[0]) == 0) {
-          scriptSave("f1.script");
-          f1CommandOptionsSave("f1_options.txt");
+          g_f1FileToRun = g_autocompleteFilenameScript;
           redFThreadStart(gThreadF1[0]);
         }
       }
-    } else if (keycode == GLFW_KEY_F2) {
-      gF2Toggle = gF2Toggle == 1 ? 0 : 1;
-    } else if (keycode == GLFW_KEY_F3) {
-      gGameMode = gGameMode == 1 ? 0 : 1;
-    } else if (keycode == GLFW_KEY_F5) {
+    } else if (keycode == GLFW_KEY_F4) { // fit code to window
+      g_resizeMainCodeWindow = 1;
+    } else if (false && keycode == GLFW_KEY_F5) {
       apeScriptRerun(0);
       if (gStopScript == 1) {
         gRunScriptOnce = 2;
       }
-    } else if (keycode == GLFW_KEY_F7) {
+    } else if (false && keycode == GLFW_KEY_F7) {
       gStopScript = 1;
-    } else if (keycode == GLFW_KEY_F9) {
+    } else if (false && keycode == GLFW_KEY_F9) {
       gStopScript = 0;
     } else if (keycode == GLFW_KEY_F11) {
       gFullscreen = gFullscreen == 0 ? 1 : 0;
@@ -3891,42 +4391,98 @@ static void dragged(RedFHandleEventParametersDrag parameters) {
   gDragAndDropCounter += 1;
 }
 
+#ifdef _WIN32
+// https://devblogs.microsoft.com/pix/taking-a-capture/
+
+#pragma comment(lib, "Shell32") // For SHGetKnownFolderPath
+
+static std::wstring GetLatestWinPixGpuCapturerPath()
+{
+    LPWSTR programFilesPath = nullptr;
+    SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFilesPath);
+
+    std::wstring pixSearchPath = programFilesPath + std::wstring(L"\\Microsoft PIX\\*");
+
+    WIN32_FIND_DATAW findData;
+    bool foundPixInstallation = false;
+    wchar_t newestVersionFound[MAX_PATH];
+
+    HANDLE hFind = FindFirstFileW(pixSearchPath.c_str(), &findData);
+    if (hFind != INVALID_HANDLE_VALUE)
+    {
+        do
+        {
+            if (((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) &&
+                 (findData.cFileName[0] != '.'))
+            {
+                if (!foundPixInstallation || wcscmp(newestVersionFound, findData.cFileName) <= 0)
+                {
+                    foundPixInstallation = true;
+                    StringCchCopyW(newestVersionFound, _countof(newestVersionFound), findData.cFileName);
+                }
+            }
+        }
+        while (FindNextFileW(hFind, &findData) != 0);
+    }
+
+    FindClose(hFind);
+
+    std::wstring out;
+
+    if (!foundPixInstallation)
+    {
+        // TODO: Error, no PIX installation found
+        return out;
+    }
+
+    wchar_t output[MAX_PATH];
+    StringCchCopyW(output, pixSearchPath.length(), pixSearchPath.data());
+    StringCchCatW(output, MAX_PATH, &newestVersionFound[0]);
+    StringCchCatW(output, MAX_PATH, L"\\WinPixGpuCapturer.dll");
+
+    out = output;
+
+    return out;
+}
+#endif
+
 int main(int argumentsCount, const char ** arguments) {
 #ifdef __linux__
   redFGetCurrentExeDir(&gCurrentExeDir, 0);
 #else
   gCurrentExeDir = (char *)calloc(1, 1);
 #endif
-  int width       = 1800;
-  int height      = 900;
-  int useOpenGL32 = 1;
+  int width       = 1100;
+  int height      = 800;
+  int useOpenGL32 = 0;
+  int showConsole = 1;
   for (int i = 0; i < argumentsCount; i += 1) {
     std::string arg = std::string(arguments[i]);
     gProgramArguments.push_back(arg);
     if (i > 0) {
       if (arg == "--help") {
         printf("OPTIONS:"                                "\n");
-        printf("  --game-mode"                           "\n");
         printf("  --fullscreen"                          "\n");
         printf("  --fullscreen-exclusive"                "\n");
         printf("  --width <value>"                       "\n");
         printf("  --height <value>"                      "\n");
         printf("  --set-imgui-font-global-scale <value>" "\n");
-        printf("  --disable-default-fkeys"               "\n");
         printf("  --disable-window-decorations"          "\n");
-        printf("  --enable-opengl21"                     "\n");
-        printf("  --disable-embree-procedures"           "\n");
-        printf("  --disable-redgpu-procedures"           "\n");
-        printf("  --disable-xatlas-procedures"           "\n");
-        printf("  --disable-fbx-procedures"              "\n");
-        printf("  --set-directory-path <value>"          "\n");
-#if defined(GAME_SCRIPT_NATIVE)
-        printf("  --load-game-library-at-start"          "\n");
-        printf("  --load-thread2-library-at-start"       "\n");
-#endif
+        printf("  --enable-opengl32"                     "\n");
+        printf("  --pix-on-windows"                      "\n");
+        printf("  --hide-console"                        "\n");
         fflush(stdout);
         exit(0);
-      } else if (arg == "--game-mode") {
+      } else if (arg == "--pix-on-windows") {
+        #ifdef _WIN32
+        std::wstring pixDllPath = GetLatestWinPixGpuCapturerPath();
+        if (pixDllPath.empty() == false) {
+          LoadLibraryW(pixDllPath.c_str());
+        }
+        #endif
+      } else if (arg == "--hide-console") {
+        showConsole = 0;
+      } else if (false && arg == "--game-mode") {
         gGameMode = 1;
         scriptLoad("game.script");
       } else if (arg == "--fullscreen") {
@@ -3948,21 +4504,21 @@ int main(int argumentsCount, const char ** arguments) {
           std::string nextArg = std::string(arguments[i + 1]);
           gImguiFontGlobalScale = std::stof(nextArg);
         }
-      } else if (arg == "--disable-default-fkeys") {
+      } else if (false && arg == "--disable-default-fkeys") {
         gDisableDefaultFkeys = 1;
       } else if (arg == "--disable-window-decorations") {
         g_windowIsDecorated = 0;
-      } else if (arg == "--enable-opengl21") {
-        useOpenGL32 = 0;
-      } else if (arg == "--disable-embree-procedures") {
+      } else if (arg == "--enable-opengl32") {
+        useOpenGL32 = 1;
+      } else if (false && arg == "--disable-embree-procedures") {
         gEmbreeIsEnabled = 0;
-      } else if (arg == "--disable-redgpu-procedures") {
+      } else if (false && arg == "--disable-redgpu-procedures") {
         gRedGpuIsEnabled = 0;
-      } else if (arg == "--disable-xatlas-procedures") {
+      } else if (false && arg == "--disable-xatlas-procedures") {
         gXatlasIsEnabled = 0;
-      } else if (arg == "--disable-fbx-procedures") {
+      } else if (false && arg == "--disable-fbx-procedures") {
         gFbxIsEnabled = 0;
-      } else if (arg == "--set-directory-path") {
+      } else if (false && arg == "--set-directory-path") {
         if (i + 1 < argumentsCount) {
 #if defined(_WIN32)
           gCurrentExeDir = _strdup(arguments[i + 1]);
@@ -3971,7 +4527,7 @@ int main(int argumentsCount, const char ** arguments) {
 #endif
         }
 #if defined(GAME_SCRIPT_NATIVE)
-      } else if (arg == "--load-game-library-at-start") {
+      } else if (false && arg == "--load-game-library-at-start") {
         std::string dir = gCurrentExeDir;
 
 #if defined(__linux__)
@@ -3982,7 +4538,7 @@ int main(int argumentsCount, const char ** arguments) {
 #error Error
 #endif
 
-      } else if (arg == "--load-thread2-library-at-start") {
+      } else if (false && arg == "--load-thread2-library-at-start") {
         std::string dir = gCurrentExeDir;
 
 #if defined(__linux__)
@@ -3997,6 +4553,23 @@ int main(int argumentsCount, const char ** arguments) {
       }
     }
   }
+  if (showConsole == 0) {
+    #ifdef _WIN32
+    FreeConsole();//DEBUG
+    #endif
+  }
+  if (argumentsCount >= 2) {
+    std::string lastArgument = arguments[argumentsCount - 1];
+    if (lastArgument.size() >= 2) {
+      if (lastArgument[0] != '-' && lastArgument[1] != '-') {
+        g_currentlyOpenedFile = lastArgument;
+      }
+    } else if (lastArgument.size() == 1) {
+      if (lastArgument[0] != '-') {
+        g_currentlyOpenedFile = lastArgument;
+      }
+    }
+  }
   RedFEvents events = {};
   events.setup         = setup;
   events.update        = update;
@@ -4013,7 +4586,7 @@ int main(int argumentsCount, const char ** arguments) {
   events.mouseExited   = mouseExited;
   events.dragged       = dragged;
   redFMain(&events, width, height, gFullscreenExclusive == 1 ? REDF_WINDOW_MODE_GAME_MODE : REDF_WINDOW_MODE_WINDOW, useOpenGL32, g_windowIsDecorated, 1, MSAA_SAMPLES_COUNT, 0, 0);
-  scriptSave("autosave.script");
+  scriptSave(g_currentlyOpenedFile);
 }
 
 #if defined(GAME_SCRIPT_NATIVE)
